#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>

#include "util.h"
#include "common.h"

#define INAFILENAME "inputA.bin"
#define INBFILENAME "inputB.bin"
#define OUTFILENAME "output.bin"

#ifdef CUDA

#include <driver_types.h>
float *calculation_cuda(float *inA, float *inB, int row, int col);

#endif

float *calculation_omp(float *inA, float *inB, int row, int col);


/* ---- main program ---- */

int main(int argc, char *argv[]) {

   double start_time, end_time;

   int i;

   float *inA, *inB, *out;
   int sizeIn, sizeOut;

   start_time = getTimeStamp();

   int rowSize,colSize;
   if (argc < 6) {
      fprintf(stderr,"Usage: %s <#nrows> <#ncols> <inputA> <inputB> <output>\n",argv[0]);
      exit(1);
   }
   
   rowSize = atoi(argv[1]);
   colSize = atoi(argv[2]);
   char *inputA = argv[3];
   char *inputB = argv[4];
   char *output = argv[5];

   int padded_row;
   inA = read_raw_matrix(inputA,TILESIZE,rowSize,colSize,&padded_row);
   if (padded_row != rowSize) {
      fprintf(stderr,"Number of rows in A is not a multiple of TILESIZE\n");
      exit(1);
   }
   inB = read_raw_matrix(inputB,TILESIZE,rowSize,colSize,&padded_row);
   if (padded_row != rowSize) {
      fprintf(stderr,"Number of rows in B is not a multiple of TILESIZE\n");
      exit(1);
   }

   sizeIn = rowSize*colSize*sizeof(float);
   sizeOut = rowSize*rowSize*sizeof(float);

#ifdef CUDA
   int cudaDeviceCount;
   cudaError_t e = cudaGetDeviceCount(&cudaDeviceCount);
   if (e != cudaSuccess) {
      cudaDeviceCount = 0;
   }
   if (cudaDeviceCount > 0) {
      out = calculation_cuda(inA,inB,rowSize,colSize); // Use first device?
   } else {
      out = calculation_omp(inA,inB,rowSize,colSize); // Use multicore
   }
#else
   out = calculation_omp(inA,inB,rowSize,colSize); // Use multicore
#endif

   //write_submatrix(out,rowSize,rowSize,rowSize,rowSize);
   FILE *outfi;
   outfi = fopen(output,"w");
   if (outfi != NULL) fwrite(out,sizeof(float),rowSize*rowSize,outfi);
   fclose(outfi);
   free(inA);
   free(inB);
   free(out);

   end_time = getTimeStamp();

   //struct timespec timeout;
   //timeout.tv_sec = 60;
   //timeout.tv_nsec = 0;
   //fprintf(stderr,"Wait %d s.\n",timeout.tv_sec);
   //while (nanosleep(&timeout,&timeout) && errno == EINTR);

   return 0;
}


